package procTest;

import static org.junit.Assert.assertEquals;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.logging.Logger;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import proc.BasicFileProcessor;
import proc.BasicMFP;
import proc.FileProcessor;

public class BasicMFPTest {

	private FileProcessor fileProcTest;
	private File report;
	private File result;
	private final String path = "src/procTest/IOFiles/";
	private Logger LOG;

	@Before
	public void setUp() {
		this.LOG = Logger.getLogger("");
		this.report = new File(this.path + "report_output");
		this.result = new File(this.path + "result_output");
		this.report.delete();
		this.result.delete();
	}

	/**
	 * All input files are good
	 */
	@Test
	public void auxNormTest1() {
		System.out.println("auxNormTest1");
		String[] fileNames = { this.path + "primary_input",
				this.path + "auxiliary_input", this.path + "result_output",
				this.path + "report_output" };
		BasicMFP.main(fileNames);
		File result = new File(this.path + "result_output");
		File report = new File(this.path + "report_output");
		assertEquals("result output file doesn't exist.", true, result.exists());
		assertEquals("report output file doesn't exist.", true, report.exists());
	}

	/**
	 * All input files are large
	 */
	@Test
	public void auxNormTest2() {
		System.out.println("auxNormTest2");
		String[] fileNames = { this.path + "primary_input_large",
				this.path + "auxiliary_input_large",
				this.path + "result_output", this.path + "report_output" };
		BasicMFP.main(fileNames);
		File result = new File(this.path + "result_output");
		File report = new File(this.path + "report_output");
		assertEquals("result output file doesn't exist.", true, result.exists());
		assertEquals("report output file doesn't exist.", true, report.exists());
	}

	/**
	 * All input files are extremely large
	 */
	@Test
	public void auxNormTest3() {
		System.out.println("auxNormTest3");
		String[] fileNames = { this.path + "primary_input_extreme",
				this.path + "auxiliary_input_extreme",
				this.path + "result_output", this.path + "report_output" };
		BasicMFP.main(fileNames);
		File result = new File(this.path + "result_output");
		File report = new File(this.path + "report_output");
		assertEquals("result output file doesn't exist.", true, result.exists());
		assertEquals("report output file doesn't exist.", true, report.exists());
	}

	// Tests for the result output files
	/**
	 * The result file should contain less than 80 bytes
	 * 
	 * @throws IOException
	 */
	@Test
	public void resultBytesTest() throws IOException {
		System.out.println("resultBytesTest");
		int byteNum = 0;
		String[] fileNames = { this.path + "primary_input",
				this.path + "auxiliary_input", this.path + "result_output",
				this.path + "report_output" };
		BasicMFP.main(fileNames);
		FileInputStream resultStream = new FileInputStream(this.path
				+ "result_output");
		int next = resultStream.read();
		while (next != -1) {
			if (next < 32 && next > 126) {
				byteNum++;
			}
			next = resultStream.read();
		}
		resultStream.close();
		assertEquals("The result file contains more than 80 bytes.", true,
				byteNum <= 80);
	}

	/**
	 * The result file should contain less than 80 bytes when the primary input
	 * is extremely large
	 * 
	 * @throws IOException
	 */
	@Test
	public void resultBytesExtTest1() throws IOException {
		System.out.println("resultBytesExtTest1");
		int byteNum = 0;
		String[] fileNames = { this.path + "primary_input_extreme",
				this.path + "auxiliary_input", this.path + "result_output",
				this.path + "report_output" };
		BasicMFP.main(fileNames);
		FileInputStream resultStream = new FileInputStream(this.path
				+ "result_output");
		int next = resultStream.read();
		while (next != -1) {
			if (next < 32 && next > 126) {
				byteNum++;
			}
			next = resultStream.read();
		}

		assertEquals("The result file contains more than 80 bytes.", true,
				byteNum <= 80);
	}

	/**
	 * The result file should contain less than 80 bytes when both the primary
	 * and auxiliary input files are extremely large
	 * 
	 * @throws IOException
	 */
	@Test
	public void resultBytesExtTest2() throws IOException {
		System.out.println("resultBytesExtTest2");
		int byteNum = 0;
		String[] fileNames = { this.path + "primary_input_extreme",
				this.path + "auxiliary_input_extreme",
				this.path + "result_output", this.path + "report_output" };
		BasicMFP.main(fileNames);
		FileInputStream resultStream = new FileInputStream(this.path
				+ "result_output");
		int next = resultStream.read();
		while (next != -1) {
			if (next < 32 && next > 126) {
				byteNum++;
			}
			next = resultStream.read();
		}

		assertEquals("The result file contains more than 80 bytes.", true,
				byteNum <= 80);
	}

	/**
	 * The result file should only contain printable bytes
	 * 
	 * @throws IOException
	 */
	@Test
	public void resultPritTest() throws IOException {
		System.out.println("resltPritTest");
		boolean result = true;
		String[] fileNames = { this.path + "primary_input",
				this.path + "auxiliary_input", this.path + "result_output",
				this.path + "report_output" };
		BasicMFP.main(fileNames);
		FileInputStream resultStream = new FileInputStream(this.path
				+ "result_output");
		int next = resultStream.read();
		while (next != -1) {
			if (next < 32 && next > 126) {
				result = false;
			}
			next = resultStream.read();
		}
		assertEquals("The result file contains bytes not printable.", true,
				result);
	}

	/**
	 * The result file should contain num_lines lines of the primary input file
	 * 
	 * @throws IOException
	 */
	@Test
	public void resultLineTest() throws IOException {
		System.out.println("resultLineTest");
		int lineNum = 0;
		String[] fileNames = { this.path + "primary_input",
				this.path + "auxiliary_input", this.path + "result_output",
				this.path + "report_output" };
		BasicMFP.main(fileNames);
		File result = new File(this.path + "result_output");
		BufferedReader br = new BufferedReader(new InputStreamReader(
				new FileInputStream(result)));
		int c;
		while ((c = br.read()) != -1) {
			if (c == '\n') {
				lineNum++;
			}
		}
		this.fileProcTest = new BasicFileProcessor(this.LOG);
		File auxFile = new File(this.path + "auxiliary_input");
		assertEquals("The result file contains more than num_lines.", true,
				lineNum <= this.fileProcTest.processAuxFile(auxFile));
	}

	/**
	 * The result file should contain num_lines lines of the primary input file
	 * when the input file is extremely large
	 * 
	 * @throws IOException
	 */
	@Test
	public void resultLineExtTest() throws IOException {
		System.out.println("resultLineExtTest");
		int lineNum = 0;
		String[] fileNames = { this.path + "primary_input_extreme",
				this.path + "auxiliary_input_extreme",
				this.path + "result_output", this.path + "report_output" };
		BasicMFP.main(fileNames);
		File result = new File(this.path + "result_output");
		BufferedReader br = new BufferedReader(new InputStreamReader(
				new FileInputStream(result)));
		int c;
		while ((c = br.read()) != -1) {
			if (c == '\n') {
				lineNum++;
			}
		}
		this.fileProcTest = new BasicFileProcessor(this.LOG);
		File auxFile = new File(this.path + "auxiliary_input_extreme");
		assertEquals("The result file contains more than num_lines.", true,
				lineNum <= this.fileProcTest.processAuxFile(auxFile));
	}

	@After
	public void deleteOuput() throws SecurityException, InterruptedException {
		this.LOG = null;

	}
}
